#include <iostream>
#include <json/json.h>
#include <json/value.h>
#include <json/reader.h>

#include <boost/beast/http.hpp>
#include <boost/beast.hpp>
#include <boost/asio.hpp>
#include <memory>
#include "CServer.h"
#include "LogicSystem.h"

#include "message.grpc.pb.h"
#include "message.pb.h"
#include "ConfigMgr.h"
#include "IOContextPool.h"
#include "hiredis.h"
#include <cassert>
#include "RedisMgr.h"

// 使用asio和beast搭建http服务器，
// asio作为网络的底层负责发送和接收数据，提供监听器等操作
// beast作为http上层负责包装以及解包等操作
namespace beast = boost::beast;															// from <boost/beast.hpp>
namespace http = beast::http;															// from <boost/beast/http.hpp>
namespace net = boost::asio;															// from <boost/asio.hpp>
using tcp = boost::asio::ip::tcp;														// from <boost/asio/ip/tcp.hpp>


void TestRedis();
void TestRedisMgr();


#include <algorithm>




int main()
{

	try
	{
		std::string gate_port_str = ConfigMgr::Inst()["GateServer"]["Port"];
		unsigned short gate_port = atoi(gate_port_str.c_str());
		
		net::io_context ioc{ 1 };													//用于监听退出
		boost::asio::signal_set signals(ioc, SIGINT, SIGTERM);						//信号注册
		signals.async_wait([&ioc](const boost::system::error_code& error, int signal_number)		//信号注册在事件树
		{

			if (error) 
			{
				return;
			}
			ioc.stop();
		});

		//std::make_shared<CServer>(ioc, gate_port)->Start();
		//CServer m_server(ioc, gate_port);
		//m_server.Start();

		//如果使用enable_shared_self，对象必须开辟于堆，且使用智能指针进行管理,否则会报weak_ptr错误
		std::shared_ptr<CServer> m_server = std::make_shared<CServer>(AsioIOServicePool::GetInstance()->GetIOService(), gate_port);				//使用asio连接池
		m_server->Start();	//从io_context池中取出一个用于监听连接事件
		ioc.run();			//定时器的ioc启动
	}
	catch (std::exception const& e)
	{
		std::cerr << "Error: " << e.what() << std::endl;
		return EXIT_FAILURE;
	}
}



void TestRedis() 
{
	//连接redis 需要启动才可以进行连接
//redis默认监听端口为6387 可以再配置文件中修改
	redisContext* c = redisConnect("127.0.0.1", 6380);

	if (c->err)
	{
		printf("Connect to redisServer faile:%s\n", c->errstr);
		redisFree(c);        return;
	}
	printf("Connect to redisServer Success\n");

	std::string redis_password = "123456";

	//C++ 的string和const char* 是完全不一样的东西，拼接字符串然后执行并返回
	//返回一个指针，说明内部返回了一个指针，不建议，有时候可能就会忘记进行管理
	redisReply* r = (redisReply*)redisCommand(c, "AUTH %s", redis_password.c_str());
	if (r->type == REDIS_REPLY_ERROR) {
		printf("Redis认证失败！\n");
	}
	else {
		printf("Redis认证成功！\n");
	}

	//为redis设置key
	const char* command1 = "set stest1 value1";

	//执行redis命令行
	r = (redisReply*)redisCommand(c, command1);

	//如果返回NULL则说明执行失败
	if (NULL == r)
	{
		printf("Execut command1 failure\n");
		redisFree(c);        return;
	}

	//如果执行失败则释放连接
	if (!(r->type == REDIS_REPLY_STATUS && (strcmp(r->str, "OK") == 0 || strcmp(r->str, "ok") == 0)))
	{
		printf("Failed to execute command[%s]\n", command1);
		freeReplyObject(r);
		redisFree(c);        return;
	}

	//执行成功 释放redisCommand执行后返回的redisReply所占用的内存
	freeReplyObject(r);
	printf("Succeed to execute command[%s]\n", command1);

	const char* command2 = "strlen stest1";
	r = (redisReply*)redisCommand(c, command2);

	//如果返回类型不是整形 则释放连接
	if (r->type != REDIS_REPLY_INTEGER)
	{
		printf("Failed to execute command[%s]\n", command2);
		freeReplyObject(r);
		redisFree(c);        return;
	}

	//获取字符串长度
	int length = r->integer;
	freeReplyObject(r);
	printf("The length of 'stest1' is %d.\n", length);
	printf("Succeed to execute command[%s]\n", command2);

	//获取redis键值对信息
	const char* command3 = "get stest1";
	r = (redisReply*)redisCommand(c, command3);
	if (r->type != REDIS_REPLY_STRING)
	{
		printf("Failed to execute command[%s]\n", command3);
		freeReplyObject(r);
		redisFree(c);        return;
	}
	printf("The value of 'stest1' is %s\n", r->str);
	freeReplyObject(r);
	printf("Succeed to execute command[%s]\n", command3);

	const char* command4 = "get stest2";
	r = (redisReply*)redisCommand(c, command4);
	if (r->type != REDIS_REPLY_NIL)
	{
		printf("Failed to execute command[%s]\n", command4);
		freeReplyObject(r);
		redisFree(c);        return;
	}
	freeReplyObject(r);
	printf("Succeed to execute command[%s]\n", command4);

	//释放连接资源
	redisFree(c);

}

void TestRedisMgr() {
	assert(RedisMgr::GetInstance()->Connect("127.0.0.1", 6380));
	assert(RedisMgr::GetInstance()->Auth("123456"));
	assert(RedisMgr::GetInstance()->Set("blogwebsite", "llfc.club"));
	std::string value = "";
	assert(RedisMgr::GetInstance()->Get("blogwebsite", value));
	assert(RedisMgr::GetInstance()->Get("nonekey", value) == false);
	assert(RedisMgr::GetInstance()->HSet("bloginfo", "blogwebsite", "llfc.club"));
	assert(RedisMgr::GetInstance()->HGet("bloginfo", "blogwebsite") != "");
	assert(RedisMgr::GetInstance()->ExistsKey("bloginfo"));
	assert(RedisMgr::GetInstance()->Del("bloginfo"));
	assert(RedisMgr::GetInstance()->Del("bloginfo"));
	assert(RedisMgr::GetInstance()->ExistsKey("bloginfo") == false);
	assert(RedisMgr::GetInstance()->LPush("lpushkey1", "lpushvalue1"));
	assert(RedisMgr::GetInstance()->LPush("lpushkey1", "lpushvalue2"));
	assert(RedisMgr::GetInstance()->LPush("lpushkey1", "lpushvalue3"));
	assert(RedisMgr::GetInstance()->RPop("lpushkey1", value));
	assert(RedisMgr::GetInstance()->RPop("lpushkey1", value));
	assert(RedisMgr::GetInstance()->LPop("lpushkey1", value));
	assert(RedisMgr::GetInstance()->LPop("lpushkey2", value) == false);
	RedisMgr::GetInstance()->Close();
}